
package com.hlkj.pay.app.ad.impl;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import java.math.BigDecimal;
import java.util.List;

import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.pojo.PageResult;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.pay.app.ad.IAdRefundOrderAppService;
import com.hlkj.pay.common.AdResultCode;
import com.hlkj.pay.common.CommonResultCode;
import com.hlkj.pay.dto.ad.AdPayOrderDto;
import com.hlkj.pay.dto.ad.query.AdPayOrderQueryDto;
import com.hlkj.pay.dto.ad.query.HlRefundOrderQueryResultDto;
import com.hlkj.pay.dto.ad.result.HlRefundDataResultDto;
import com.hlkj.pay.enums.PayOrderEnums;
import com.hlkj.pay.gateway.ad.IAdOrderGateway;
import com.hlkj.pay.infrastructure.model.ad.AdInfoConfigDO;
import com.hlkj.pay.infrastructure.model.ad.AdPayOrderDO;
import com.hlkj.pay.infrastructure.model.ad.AdRefundOrderApplyDO;
import com.hlkj.pay.infrastructure.model.ad.AdRefundOrderDO;
import com.hlkj.pay.service.ad.IAdInfoService;
import com.hlkj.pay.service.ad.IAdPayOrderService;
import com.hlkj.pay.service.ad.IAdRefundOrderService;
import com.hlkj.pay.util.MerchantUtils;
import com.hlkj.pay.util.OrderCodeUtil;
import com.hlkj.pay.vo.ad.req.AdOrderRefundApplyReq;
import com.hlkj.pay.vo.ad.req.AdOrderRefundApproveReq;

import cn.hutool.core.bean.BeanUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author HlpayTeam
 * @date 2024/10/23 13:05
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AdRefundOrderAppServiceImpl implements IAdRefundOrderAppService {

    private final IAdPayOrderService adPayOrderService;

    private final IAdRefundOrderService adRefundOrderService;

    private final IAdInfoService adInfoService;

    private final OrderCodeUtil orderCodeUtil;

    private final AdPayOrderMessageHandler adPayOrderMessageHandler;

    private final IAdOrderGateway adOrderGateway;

    @Override
    public CommonResult<Void> applyRefundOrder(AdOrderRefundApplyReq adOrderRefundApplyReq) {
        log.info("applyRefundOrder adOrderRefundApplyReq:{}", JsonUtils.toJsonString(adOrderRefundApplyReq));
        try {
            AdPayOrderDO adPayOrderDO = null;
            if (StringUtils.hasText(adOrderRefundApplyReq.getMchOrderNo())) {
                adPayOrderDO = adPayOrderService.queryDetailCache(adOrderRefundApplyReq.getMchOrderNo());
                if (adPayOrderDO == null) {
                    adPayOrderDO = adPayOrderService.queryDetailByInsOrderNo(adOrderRefundApplyReq.getMchOrderNo());
                }
                if (adPayOrderDO == null) {
                    AdPayOrderQueryDto adPayOrderQueryDto = new AdPayOrderQueryDto();
                    adPayOrderQueryDto.setState(PayOrderEnums.PAY_ORDER_STATUS.SUCCESS.getCode());
                    adPayOrderQueryDto.setPhone(adOrderRefundApplyReq.getMchOrderNo());
                    adPayOrderQueryDto.setRefundStatus(PayOrderEnums.ORDER_REFUND_STATUS.NO_REFUND.getCode());
                    adPayOrderQueryDto.setPageNo(0);
                    adPayOrderQueryDto.setPageSize(1);
                    PageResult<AdPayOrderDto> orderDtoPageResult = adPayOrderService.queryPage(adPayOrderQueryDto);
                    List<AdPayOrderDto> adPayOrderDtos = orderDtoPageResult.getList();
                    // if (!CollectionUtils.isEmpty(adPayOrderDtos)) {
                    //     AdRefundOrderQueryDto adRefundOrderQueryDto = new AdRefundOrderQueryDto();
                    //     adRefundOrderQueryDto.setPhone(adOrderRefundApplyReq.getMchOrderNo());
                    //     adRefundOrderQueryDto.setApplyStatus(PayOrderEnums.REFUND_APPLY_STATUS.WAIT_APPROVE.getCode());
                    //     PageResult<AdRefundOrderApplyDO> adRefundOrderApplyDOPageResult = adRefundOrderService.queryApplyPage(adRefundOrderQueryDto);
                    //     List<AdRefundOrderApplyDO> adRefundOrderApplList = adRefundOrderApplyDOPageResult.getList();
                    //     if (!CollectionUtils.isEmpty(adRefundOrderApplList)) {
                    //         return CommonResult.error(AdResultCode.REFUND_APPLY_ORDER_EXITS);
                    //     }
                    // }
                    if(!CollectionUtils.isEmpty(adPayOrderDtos)){
                        adPayOrderDO = adPayOrderDtos.get(0);
                    }
                }
            }
            else if (StringUtils.hasText(adOrderRefundApplyReq.getInsOrderNo())) {
                adPayOrderDO = adPayOrderService.queryDetailByInsOrderNo(adOrderRefundApplyReq.getMchOrderNo());
            }
            else if (StringUtils.hasText(adOrderRefundApplyReq.getPhone())) {
                AdPayOrderQueryDto adPayOrderQueryDto=new AdPayOrderQueryDto();
                adPayOrderQueryDto.setPhone(adOrderRefundApplyReq.getPhone());
                adPayOrderQueryDto.setRefundStatus(PayOrderEnums.ORDER_REFUND_STATUS.NO_REFUND.getCode());
                adPayOrderQueryDto.setPageNo(1);
                adPayOrderQueryDto.setPageSize(1);
                PageResult<AdPayOrderDto> orderDtoPageResult = adPayOrderService.queryPage(adPayOrderQueryDto);
                List<AdPayOrderDto> adPayOrderDtos = orderDtoPageResult.getList();
                if(!CollectionUtils.isEmpty(adPayOrderDtos)){
                    adPayOrderDO = adPayOrderDtos.get(0);
                }
            }
            if (adPayOrderDO == null) {
                return CommonResult.error(AdResultCode.PAY_ORDER_NOT_EXITS);
            }
            PayOrderEnums.PAY_ORDER_STATUS payOrderStatus = PayOrderEnums.PAY_ORDER_STATUS.from(adPayOrderDO.getState());
            if (!PayOrderEnums.PAY_ORDER_STATUS.SUCCESS.getCode().equals(adPayOrderDO.getState())) {
                return CommonResult.error(AdResultCode.PAY_ORDER_CANNOT_REFUND.getCode(), "当前订单状态为" + payOrderStatus.getMsg() + ",不可退款");
            }
            BigDecimal subtract = adPayOrderDO.getAmount().subtract(adPayOrderDO.getRefundAmount());
            // 判断可退款金额
            if (StringUtils.hasText(adOrderRefundApplyReq.getRefundAmount())) {
                if (subtract.compareTo(new BigDecimal(adOrderRefundApplyReq.getRefundAmount())) < 0) {
                    return CommonResult.error(AdResultCode.AD_REFUND_AMOUNT_ERROR);
                }
            }
            else {
                adOrderRefundApplyReq.setRefundAmount(MerchantUtils.bigDecimalToString(subtract));
            }
            AdRefundOrderApplyDO refundOrderApplyDO = adRefundOrderService.queryLastOne(adPayOrderDO.getMchOrderNo());
            if (refundOrderApplyDO != null && PayOrderEnums.REFUND_APPLY_STATUS.WAIT_APPROVE.getCode().equals(refundOrderApplyDO.getApplyStatus())) {
                return CommonResult.error(AdResultCode.REFUND_APPLY_ORDER_WAIT_APPROVE);
            }
            AdRefundOrderApplyDO adRefundOrderApplyDO = BeanUtil.copyProperties(adOrderRefundApplyReq, AdRefundOrderApplyDO.class);
            adRefundOrderApplyDO.setApplyStatus(PayOrderEnums.REFUND_APPLY_STATUS.WAIT_APPROVE.getCode());
            adRefundOrderApplyDO.setRefundApplyNo(orderCodeUtil.orderNo(PayOrderEnums.ORDER_NO_TYPE.REFUND_APPLY));
            adRefundOrderApplyDO.setAdId(adPayOrderDO.getAdId());
            adRefundOrderApplyDO.setMchOrderNo(adPayOrderDO.getMchOrderNo());
            if (!StringUtils.hasText(adOrderRefundApplyReq.getPhone())) {
                adRefundOrderApplyDO.setPhone(adPayOrderDO.getPhone());
            }
            adRefundOrderApplyDO.setInsOrderNo(adPayOrderDO.getInsOrderNo());
            adRefundOrderService.addRefundOrderApply(adRefundOrderApplyDO);
            return CommonResult.success();
        }
        catch (Exception e) {
            e.printStackTrace();
            log.error("applyRefundOrder error:{}", e.getMessage(),e);
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }
    }

    @Override
    public CommonResult<Void> approveRefundOrder(AdOrderRefundApproveReq adOrderRefundApproveReq) {
        log.info("approveRefundOrder adOrderRefundApproveReq:{}", JsonUtils.toJsonString(adOrderRefundApproveReq));
        try {
            AdRefundOrderApplyDO refundOrderApplyDO = adRefundOrderService.queryByRefundApplyNo(adOrderRefundApproveReq.getRefundApplyNo());
            if (refundOrderApplyDO == null) {
                return CommonResult.error(AdResultCode.REFUND_APPLY_ORDER_NOT_EXITS);
            }
            if (refundOrderApplyDO.getApplyStatus().equals(adOrderRefundApproveReq.getApplyStatus())) {
                return CommonResult.error(AdResultCode.REFUND_APPLY_ORDER_STATUS_NOT_CHANGE);
            }
            AdRefundOrderApplyDO adRefundOrderApplyDO = BeanUtil.copyProperties(adOrderRefundApproveReq, AdRefundOrderApplyDO.class);
            adRefundOrderApplyDO.setId(refundOrderApplyDO.getId());
            if (adOrderRefundApproveReq.getApplyStatus().equals(PayOrderEnums.REFUND_APPLY_STATUS.APPROVE.getCode())) {
                // AdPayOrderDO payOrderDO = adPayOrderService.queryDetailCache(refundOrderApplyDO.getMchOrderNo());
                // if (payOrderDO == null) {
                //     return CommonResult.error(AdResultCode.PAY_ORDER_NOT_EXITS);
                // }
                // // 实际退款
                // CommonResult<AdRefundOrderDO> commonResult = processRefund(refundOrderApplyDO, payOrderDO);
                // if (!commonResult.isSuccess()) {
                //     return CommonResult.error(commonResult.getCode(), commonResult.getMsg());
                // }
                // AdRefundOrderDO adRefundOrderDO = commonResult.getData();
                // AdPayOrderDO updatePayOrderDO = new AdPayOrderDO();
                // updatePayOrderDO.setId(payOrderDO.getId());
                // updatePayOrderDO.setRefundAmount(adRefundOrderDO.getTotalRefundAmount());
                // adPayOrderService.updatePayOrder(adRefundOrderDO.getMchOrderNo(), updatePayOrderDO);
                // adPayOrderMessageHandler.refundOrder(adRefundOrderDO);
                // adRefundOrderApplyDO.setRefundStatus(adRefundOrderDO.getRefundStatus());
            }
            adRefundOrderService.updateRefundOrderApply(adRefundOrderApplyDO);
            return CommonResult.success();
        }
        catch (Exception e) {
            e.printStackTrace();
            log.error("approveRefundOrder error:{}", e.getMessage(),e);
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }
    }

    @Override
    public boolean queryRefundStatus(String orderNo) {
        AdRefundOrderDO adRefundOrderDO = adRefundOrderService.queryDetail(orderNo);
        if (adRefundOrderDO == null) {
            return false;
        }
        PayOrderEnums.REFUND_STATUS refundStatus = PayOrderEnums.REFUND_STATUS.from(adRefundOrderDO.getRefundStatus());
        switch (refundStatus) {
            case REFUNDING:
                try {
                    AdInfoConfigDO adInfoConfigDO = adInfoService.queryConfigByAdId(adRefundOrderDO.getAdId());
                    HlRefundOrderQueryResultDto refundDataDto = adOrderGateway.queryRefundOrder(adRefundOrderDO, adInfoConfigDO);
                    if (refundDataDto != null) {
                        if (refundDataDto.getCode() != null && refundDataDto.getCode() == 1) {
                            HlRefundOrderQueryResultDto.RefundOrderData refundDataDtoData = (HlRefundOrderQueryResultDto.RefundOrderData) refundDataDto.getData();
                            // 订单状态，0=退款失败，1=初始化，2=退款中，3=退款成功，
                            PayOrderEnums.REFUND_STATUS updateRefundStatus = null;
                            switch (refundDataDtoData.getState()) {
                                case "0":
                                    updateRefundStatus = PayOrderEnums.REFUND_STATUS.FAIL;
                                    break;
                                case "3":
                                    updateRefundStatus = PayOrderEnums.REFUND_STATUS.REFUND;
                                    break;
                                default:
                                    return true;
                            }
                            if (updateRefundStatus != null) {
                                AdRefundOrderDO updateRefundOrderDO = new AdRefundOrderDO();
                                updateRefundOrderDO.setId(adRefundOrderDO.getId());
                                updateRefundOrderDO.setRefundStatus(refundStatus.getCode());
                                updateRefundOrderDO.setRemark(refundDataDtoData.getRefund_reason());
                                if (refundDataDtoData.getSuccess_time() != null) {
                                    updateRefundOrderDO.setSuccessTime(Long.valueOf(refundDataDtoData.getSuccess_time()) * 1000l);
                                }
                                adRefundOrderService.updateRefundOrder(adRefundOrderDO.getRefundOrderNo(), adRefundOrderDO.getRefundApplyNo(), updateRefundOrderDO);
                                return false;
                            }
                        }
                        else {
                            return true;
                        }
                    }
                    else {
                        return true;
                    }
                }
                catch (Exception e) {
                    log.info("查询退款报错:{}", e.getMessage());
                    return true;
                }
        }
        return false;
    }

    @Override
    public CommonResult<Void> createRefundOrder(AdOrderRefundApplyReq adOrderRefundApplyReq) {
        log.info("createRefundOrder adOrderRefundApplyReq:{}", JsonUtils.toJsonString(adOrderRefundApplyReq));
        try {
            if (!StringUtils.hasText(adOrderRefundApplyReq.getMchOrderNo())) {
                return CommonResult.error(CommonResultCode.PARAMETER_MISSING);
            }
            AdRefundOrderApplyDO refundOrderApplyDO = adRefundOrderService.queryLastOne(adOrderRefundApplyReq.getMchOrderNo());
            if (refundOrderApplyDO != null && PayOrderEnums.REFUND_APPLY_STATUS.WAIT_APPROVE.getCode().equals(refundOrderApplyDO.getApplyStatus())) {
                return CommonResult.error(AdResultCode.REFUND_APPLY_ORDER_WAIT_APPROVE);
            }
            AdPayOrderDO adPayOrderDO = adPayOrderService.queryDetailCache(adOrderRefundApplyReq.getMchOrderNo());
            if (adPayOrderDO == null) {
                return CommonResult.error(AdResultCode.PAY_ORDER_NOT_EXITS);
            }
            PayOrderEnums.PAY_ORDER_STATUS payOrderStatus = PayOrderEnums.PAY_ORDER_STATUS.from(adPayOrderDO.getState());
            if (!PayOrderEnums.PAY_ORDER_STATUS.SUCCESS.getCode().equals(adPayOrderDO.getState())) {
                return CommonResult.error(AdResultCode.PAY_ORDER_CANNOT_REFUND.getCode(), "当前订单状态为" + payOrderStatus.getMsg() + ",不可退款");
            }
            BigDecimal subtract = adPayOrderDO.getAmount().subtract(adPayOrderDO.getRefundAmount());
            // 判断可退款金额
            if (subtract.compareTo(new BigDecimal(adOrderRefundApplyReq.getRefundAmount())) < 0) {
                return CommonResult.error(AdResultCode.AD_REFUND_AMOUNT_ERROR);
            }
            AdRefundOrderApplyDO adRefundOrderApplyDO = BeanUtil.copyProperties(adOrderRefundApplyReq, AdRefundOrderApplyDO.class);
            adRefundOrderApplyDO.setRefundAmount(new BigDecimal(adOrderRefundApplyReq.getRefundAmount()));
            adRefundOrderApplyDO.setApplyStatus(PayOrderEnums.REFUND_APPLY_STATUS.APPROVE.getCode());
            adRefundOrderApplyDO.setRefundApplyNo(orderCodeUtil.orderNo(PayOrderEnums.ORDER_NO_TYPE.REFUND_APPLY));
            adRefundOrderApplyDO.setAdId(adPayOrderDO.getAdId());
            adRefundOrderApplyDO.setMchOrderNo(adPayOrderDO.getMchOrderNo());
            adRefundOrderApplyDO.setRefundReason("一键退款");
            adRefundOrderApplyDO.setInsOrderNo(adPayOrderDO.getInsOrderNo());
            adRefundOrderApplyDO.setPhone(adPayOrderDO.getPhone());
            // 实际退款
            adRefundOrderApplyDO.setRefundStatus(PayOrderEnums.REFUND_STATUS.REFUNDING.getCode());
            CommonResult<AdRefundOrderDO> commonResult = processRefund(adRefundOrderApplyDO, adPayOrderDO);
            if (!commonResult.isSuccess()) {
                return CommonResult.error(commonResult.getCode(), commonResult.getMsg());
            }
            AdRefundOrderDO adRefundOrderDO = commonResult.getData();
            AdPayOrderDO updatePayOrderDO = new AdPayOrderDO();
            updatePayOrderDO.setId(adPayOrderDO.getId());
            updatePayOrderDO.setRefundAmount(adRefundOrderDO.getTotalRefundAmount());
            updatePayOrderDO.setRefundStatus(adRefundOrderDO.getRefundStatus());
            // 更新支付订单 里面的总退款金额
            adPayOrderService.updatePayOrder(adRefundOrderDO.getMchOrderNo(), updatePayOrderDO);
            adPayOrderMessageHandler.refundOrder(adRefundOrderDO);
            // 更新退款状态
            adRefundOrderApplyDO.setRefundStatus(adRefundOrderDO.getRefundStatus());
            adRefundOrderService.addRefundOrderApply(adRefundOrderApplyDO);
            return CommonResult.success();
        }
        catch (Exception e) {
            e.printStackTrace();
            log.error("createRefundOrder error:{}", e.getMessage(), e);
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }
    }

    CommonResult<AdRefundOrderDO> processRefund(AdRefundOrderApplyDO adRefundOrderApplyDO, AdPayOrderDO payOrderDO) {
        AdInfoConfigDO adInfoConfigDO = adInfoService.queryConfigByAdId(adRefundOrderApplyDO.getAdId());
        AdRefundOrderDO adRefundOrderDO = refundOrder(adRefundOrderApplyDO, adInfoConfigDO);
        adRefundOrderDO.setTotalRefundAmount(payOrderDO.getRefundAmount().add(adRefundOrderDO.getRefundAmount()));
        if (payOrderDO.getPayAmount() != null) {
            adRefundOrderDO.setAmount(payOrderDO.getPayAmount());
        }
        else {
            adRefundOrderDO.setAmount(payOrderDO.getAmount());
        }
        try {
            HlRefundDataResultDto hlRefundDataResultDto = adOrderGateway.submitRefundOrder(adRefundOrderDO, adInfoConfigDO);
            if (hlRefundDataResultDto != null) {
                if (hlRefundDataResultDto.getCode() != null && hlRefundDataResultDto.getCode() == 1) {
                    HlRefundDataResultDto.DataBean dataBean = JsonUtils.parseObject(JsonUtils.toJsonString(hlRefundDataResultDto.getData()), HlRefundDataResultDto.DataBean.class);
                    if (dataBean.getState() == 0) {
                        return CommonResult.error(AdResultCode.REFUND_ORDER_FAIL.getCode(), dataBean.getErr_msg());
                    }
                    else {
                        if (dataBean.getState() == 3) {
                            adRefundOrderDO.setRefundStatus(PayOrderEnums.REFUND_STATUS.REFUND.getCode());
                            if (dataBean.getRefund_amount() != null) {
                                adRefundOrderDO.setActualRefundAmount(new BigDecimal(dataBean.getRefund_amount()));
                            }
                            else {
                                adRefundOrderDO.setActualRefundAmount(adRefundOrderDO.getRefundAmount());
                            }
                        }
                        else if (dataBean.getState() == 2) {
                            adRefundOrderDO.setRefundStatus(PayOrderEnums.REFUND_STATUS.REFUNDING.getCode());
                        }
                        adRefundOrderService.addRefundOrder(adRefundOrderDO);
                        return CommonResult.success(adRefundOrderDO);
                    }
                }
                else {
                    log.error("汇联退款生成失败" + JsonUtils.toJsonString(hlRefundDataResultDto));
                    return CommonResult.error(AdResultCode.REFUND_ORDER_FAIL.getCode(), hlRefundDataResultDto.getMsg());
                }
            }
            else {
                return CommonResult.error(AdResultCode.REFUND_ORDER_FAIL);
            }
        }
        catch (Exception e) {
            e.printStackTrace();
            log.error("");
            return CommonResult.error(AdResultCode.REFUND_ORDER_FAIL);
        }
    }

    AdRefundOrderDO refundOrder(AdRefundOrderApplyDO adRefundOrderApplyDO, AdInfoConfigDO adInfoConfigDO) {
        AdRefundOrderDO adRefundOrderDO = new AdRefundOrderDO();
        adRefundOrderDO.setRefundOrderNo(orderCodeUtil.orderNo(PayOrderEnums.ORDER_NO_TYPE.REFUND));
        adRefundOrderDO.setRefundApplyNo(adRefundOrderApplyDO.getRefundApplyNo());
        adRefundOrderDO.setMchOrderNo(adRefundOrderApplyDO.getMchOrderNo());
        adRefundOrderDO.setSn(adInfoConfigDO.getSn());
        adRefundOrderDO.setAppId(adInfoConfigDO.getAppId());
        adRefundOrderDO.setAdId(adRefundOrderApplyDO.getAdId());
        adRefundOrderDO.setRefundReason(adRefundOrderApplyDO.getRefundReason());
        adRefundOrderDO.setRefundStatus(PayOrderEnums.REFUND_STATUS.INIT.getCode());
        adRefundOrderDO.setRefundAmount(adRefundOrderApplyDO.getRefundAmount());
        return adRefundOrderDO;
    }
}
